using System;
using Geometry;
using Unity.Mathematics;

namespace Cesium3DTilesSelection
{
    public class CullingVolume
    {
        /**
 * @brief The left plane of the culling volume.
 *
 * Defaults to (0,0,1), with a distance of 0.
 */
        public Plane leftPlane = new Plane(new double3(0.0, 0.0, 1.0), 0.0);

        /**
         * @brief The right plane of the culling volume.
         *
         * Defaults to (0,0,1), with a distance of 0.
         */
        public Plane rightPlane = new Plane(new double3(0.0, 0.0, 1.0), 0.0);

        /**
         * @brief The top plane of the culling volume.
         *
         * Defaults to (0,0,1), with a distance of 0.
         */
        public Plane topPlane = new Plane(new double3(0.0, 0.0, 1.0), 0.0);

        /**
         * @brief The bottom plane of the culling volume.
         *
         * Defaults to (0,0,1), with a distance of 0.
         */
        public Plane bottomPlane = new Plane(new double3(0.0, 0.0, 1.0), 0.0);
        public static CullingVolume createCullingVolume(double3 position, double3 direction, double3 up, double fovx, double fovy)
        {
            double t = math.tan(0.5 * fovy);
            double b = -t;
            double r = math.tan(0.5 * fovx);
            double l = -r;

            double n = 1.0;

            // TODO: this is all ported directly from CesiumJS, can probably be refactored
            // to be more efficient with GLM.

            double3 right = math.cross(direction, up);

            double3 nearCenter = direction * n;
            nearCenter = position + nearCenter;

            // Left plane computation
            double3 normal = right * l;
            normal = nearCenter + normal;
            normal = normal - position;
            normal = math.normalize(normal);
            normal = math.cross(normal, up);
            normal = math.normalize(normal);

            Plane leftPlane = new Plane(normal, -math.dot(normal, position));

            // Right plane computation
            normal = right * r;
            normal = nearCenter + normal;
            normal = normal - position;
            normal = math.cross(up, normal);
            normal = math.normalize(normal);

            Plane rightPlane = new Plane(normal, -math.dot(normal, position));

            // Bottom plane computation
            normal = up * b;
            normal = nearCenter + normal;
            normal = normal - position;
            normal = math.cross(right, normal);
            normal = math.normalize(normal);

            Plane bottomPlane = new Plane(normal, -math.dot(normal, position));

            // Top plane computation
            normal = up * t;
            normal = nearCenter + normal;
            normal = normal - position;
            normal = math.cross(normal, right);
            normal = math.normalize(normal);

            Plane topPlane = new Plane(normal, -math.dot(normal, position));

            CullingVolume result = new CullingVolume();
            result.leftPlane = leftPlane;
            result.rightPlane = rightPlane;
            result.topPlane = topPlane;
            result.bottomPlane = bottomPlane;
            return result;
        }
    }
}